package pt.cp.commands;

import design.patterns.command.Command;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import static org.jsoup.Connection.Response;

public class GetTimeTables extends Command<GetTimeTables.Entity> {
    public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36";
    private static final String CALLER_ADDRESS = "http://www.cp.pt/cp/displayPage.do?vgnextoid=a4f6f9e12a584010VgnVCM1000007b01a8c0RCRD";
    private static final String ACTION_ADDRESS = "http://www.cp.pt/cp/searchTimetable.do";

    private final Connection connection;

    public GetTimeTables() {
        try {
            Response response = Jsoup
                    .connect(CALLER_ADDRESS)
                    .execute();

            connection = Jsoup
                    .connect(ACTION_ADDRESS)
                    .userAgent(USER_AGENT)
                    .cookies(response.cookies())
                    .referrer(CALLER_ADDRESS);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void protectedExecute() throws Exception {
        try {
            final Document document = connection.post();

            onAborted((o, arg) -> {
                String filename = "GetTimeTableTest." + System.currentTimeMillis() + ".html";
                try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
                    writer.write(document.toString());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });

            final Elements trs = document
                    .select("table.fd_content").get(1)
                    .select("tr");

            Entity entity = new Entity();

            boolean first = true;
            for (Element tr : trs) {
                Elements tds = tr.select("td");

                if (tds.size() != 9)
                    continue;

                if (first) {
                    first = false;
                    continue;
                }

                entity.add(new GetTimeTables.Item(tds));
            }

            setResult(entity);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private GetTimeTables set(String key, String value) {
        connection.data(key, value);
        return this;
    }

    public GetTimeTables setDepart(String depart) {
        return set("depart", depart);
    }

    public GetTimeTables setArrival(String arrival) {
        return set("arrival", arrival);
    }

    public GetTimeTables setDate(String date) {
        return set("date", date);
    }

    public GetTimeTables setTime(String time) {
        return set("time", time);
    }

    public GetTimeTables setReturnDate(String returnDate) {
        return set("returnDate", returnDate);
    }

    public GetTimeTables setReturnTime(String returnTime) {
        return set("returnTime", returnTime);
    }

    public GetTimeTables setAllServices(String allServices) {
        return set("allServices", allServices);
    }

    public static class Item {
        private final String service;
        private final String departure;
        private final String arrival;
        private final String duration;

        public Item(Elements tds) {
            service = tds.get(2).text();
            departure = tds.get(4).text();
            arrival = tds.get(5).text();
            duration = tds.get(6).text();
        }

        public String getService() {
            return service;
        }

        public String getDeparture() {
            return departure;
        }

        public String getArrival() {
            return arrival;
        }

        public String getDuration() {
            return duration;
        }
    }

    public static class Entity extends model.HashEntity<Item> {
        public Entity() {
            super(Item[].class, Item.class);
        }

        @Override
        protected void parse() {
        }
    }
}
